package com.example.java_doc_searcher.searcher;

import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

public class DocSearcher {
    private static  String STOP_WORD_PATH=null;
    static {
        if(Config.isOnline){
            STOP_WORD_PATH="/root/searcher/stop_word.txt";
        }else {
            STOP_WORD_PATH="E:\\doc_searcher_index2\\stop_word.txt";
        }
    }
    private HashSet<String> stopWords=new HashSet<>();
    private Index index=new Index();
    public DocSearcher(){

        index.load();
        loadStopWords();
    }
    public List<Result> search(String query){
        List<Term> oldterms= ToAnalysis.parse(query).getTerms();
        List<Term> terms=new ArrayList<>();
        for(Term term:oldterms){
            if(stopWords.contains(term.getName())){
                continue;
            }
            terms.add(term);
        }
        List<List<Weight>> termResult=new ArrayList<>();
        for(Term term:terms){
            String word=term.getName();
            List<Weight> invertedList=index.getInverted(word);
            if(invertedList==null){
                continue;
            }
            termResult.add(invertedList);
        }
        List<Weight> allTermResult=mergeResult(termResult);
        allTermResult.sort(new Comparator<Weight>() {
            @Override
            public int compare(Weight o1, Weight o2) {
                return o2.getWeight() - o1.getWeight();
            }
        });
        List<Result> results=new ArrayList<>();
        for(Weight weight:allTermResult){
            DocInfo docInfo=index.getDocInfo(weight.getDocId());
            Result result=new Result();
            result.setTitle(docInfo.getTitle());
            result.setUrl(docInfo.getUrl());
            result.setDesc(GenDesc(docInfo.getContent(),terms));
            results.add(result);
        }
        return results;
    }

    static class Pos{
        public int row;
        public int col;

        public Pos(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }

    private List<Weight> mergeResult(List<List<Weight>> source) {
        for(List<Weight> curRow: source){
            curRow.sort(new Comparator<Weight>() {
                @Override
                public int compare(Weight o1, Weight o2) {
                    return o1.getDocId()-o2.getDocId();
                }
            });
        }

        List<Weight>target=new ArrayList<>();
        PriorityQueue<Pos> queue=new PriorityQueue<>(new Comparator<Pos>() {
            @Override
            public int compare(Pos o1, Pos o2) {
                Weight w1=source.get(o1.row).get(o1.col);
                Weight w2=source.get(o2.row).get(o2.col);
                return w1.getDocId()-w2.getDocId();
            }
        });

        for(int row=0;row<source.size();row++){
            queue.offer(new Pos(row,0));
        }
        while (!queue.isEmpty()){
            Pos minPos=queue.poll();
            Weight curWeight=source.get(minPos.row).get(minPos.col);
            if(target.size()>0){
                Weight lastWeight=target.get(target.size()-1);
                if(lastWeight.getDocId()==curWeight.getDocId()){
                    lastWeight.setWeight(lastWeight.getWeight()+curWeight.getWeight());
                }else{
                    target.add(curWeight);
                }
            }else{
                target.add(curWeight);
            }
            Pos newPos=new Pos(minPos.row,minPos.col+1);
            if(newPos.col>=source.get(newPos.row).size()){
                continue;
            }
            queue.offer(newPos);
        }
        return target;
    }

    private String GenDesc(String content, List<Term> terms) {
        int firstPos=-1;
        for(Term term:terms){
            String word=term.getName();
            content=content.toLowerCase().replaceAll("\\b"+word+"\\b"," "+word+" ");
            firstPos=content.indexOf(" "+word+" ");
            if(firstPos>=0){
                break;
            }
        }
        if(firstPos==-1){
            if(content.length()>160){
                return content.substring(0,160)+"...";
            }
            return content;
        }
        String desc="";
        int descBeg=firstPos<60?0:firstPos-60;
        if(descBeg+160>content.length()){
            desc=content.substring(descBeg);
        }else{
            desc=content.substring(descBeg,descBeg+160)+"...";
        }
        for(Term term:terms){
            String word=term.getName();
            desc=desc.replaceAll("(?i)"+word+" ","<i> "+word+" </i>");
        }
        return desc;
    }

    public void loadStopWords(){
        try(BufferedReader bufferedReader=new BufferedReader(new FileReader(STOP_WORD_PATH))){
            while (true){
                String line=bufferedReader.readLine();
                if(line==null){
                    break;
                }
                stopWords.add(line);
            }
        } catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        DocSearcher docSearcher=new DocSearcher();
        Scanner scanner=new Scanner(System.in);
        while(true){
            System.out.print("-> ");
            String query=scanner.next();
            List<Result> results=docSearcher.search(query);
            for(Result result:results){
                System.out.println("================================="  );
                System.out.println(result);
            }
        }
    }
}
